`define OP_AND   8'h00
`define OP_ANDI  8'h01
`define OP_NAND  8'h02
`define OP_NANDI 8'h03
`define OP_OR    8'h04
`define OP_ORI   8'h05
`define OP_NOR   8'h06
`define OP_NORI  8'h07
`define OP_XOR   8'h08
`define OP_XORI  8'h09
`define OP_EQ    8'h10
`define OP_EQI   8'h11
`define OP_NE    8'h12
`define OP_NEI   8'h13
`define OP_LT    8'h14
`define OP_LTI   8'h15
`define OP_LE    8'h16
`define OP_LEI   8'h17
`define OP_ADD   8'h20
`define OP_ADDI  8'h21
`define OP_SUB   8'h22
`define OP_SUBI  8'h23
`define OP_LW    8'h40
`define OP_RCTL  8'h50
`define OP_SW    8'h60
`define OP_WCTL  8'h70
`define OP_JRL   8'h80
`define OP_BEQ   8'h90
`define OP_BEQZ  8'h91
`define OP_BNE   8'h92
`define OP_BNEZ  8'h93

`define OP_BITS  IWORD[31:24]
`define RD_BITS  IWORD[23:20]
`define RS_BITS  IWORD[19:16]
`define RT_BITS  IWORD[15:12]
`define IM_BITS  IWORD[15:00]

`define RX_BITS  4'bXXXX

module CtlRReg(IWORD,RREGNO1,RREGNO2);
  input  wire [31:0] IWORD;
  output wire [3:0] RREGNO1,RREGNO2;
  wire reg1rd=IWORD[31]&&IWORD[28]&&IWORD[24];
  assign RREGNO1=reg1rd?`RD_BITS:`RS_BITS;
  wire reg2rt=(!IWORD[31])&&(!IWORD[30]);
  assign RREGNO2=reg2rt?`RT_BITS:`RD_BITS;
endmodule

module CtlWReg(IWORD,WREGNO,WRREG);
  input  wire [31:0] IWORD;
  output  wire [3:0] WREGNO;
  output  wire WRREG;
  wire isWrReg=(!IWORD[31]&&!IWORD[30]&&IWORD!=32'b0) || (IWORD[31]&&!IWORD[28]) || (IWORD[30]&&!IWORD[29]); //alu !iword=32'b0, lw, jrl
	//mask the reti instruction
  wire notRETI, notWCTL, notRCTL;
  assign notRETI = (IWORD==32'h80CC0000) ? 1'b0:
							1'b1;
  assign notWCTL = (IWORD[31:24]==8'h70) ? 1'b0:
							1'b1;
  assign notRCTL = (IWORD[31:24]==8'h50) ? 1'b0:
							1'b1;
							
  assign WRREG=(isWrReg) && notRETI && notWCTL && notRCTL;
  assign WREGNO=(isWrReg)?`RD_BITS : `RX_BITS;
endmodule

module CtlImm(IWORD,IMMVAL);
  parameter DBITS;
  input  wire [31:0] IWORD;
  output wire [31:0] IMMVAL;
  wire [31:0] tempImmval={{(DBITS-16){IWORD[15]}},`IM_BITS};
  assign IMMVAL= (IWORD[31])?tempImmval<<2 : tempImmval;
endmodule

module CtlALUIn(IWORD,ALUIN2Z,ALUIN2I);
  input  wire [31:0] IWORD;
  output wire  ALUIN2Z,ALUIN2I;
  wire ax0check = (!IWORD[31]&&!IWORD[30]&&!IWORD[24]) || (IWORD[31]&&IWORD[28]&&!IWORD[24]);//even ALU, BEQ, BNE
  wire a01check = (!IWORD[31]&&!IWORD[30]&&IWORD[24]) || (IWORD[30]) || (IWORD[31] && !IWORD[28]);// alu odd, lw sw, jrl
  wire a11check = (IWORD[31]&&IWORD[28]&&IWORD[24]); //odd branch
  assign {ALUIN2Z,ALUIN2I}=
							(ax0check) ? 2'bX0:
							(a01check) ? 2'b01:
							(a11check) ? 2'b11:
										 2'bXX;
endmodule

module CtlALU(IWORD,
              ALULOG,LOGAND,LOGOR,LOGXOR,LOGNOT,
              ADDSUB,
              ALUCMP,CMPEQ,CMPLT,CMPNOT,
              ALUARI);
	input  wire [31:0] IWORD;
	output wire  ALULOG,LOGAND,LOGOR,LOGXOR,LOGNOT,
				ADDSUB,
				ALUCMP,CMPEQ,CMPLT,CMPNOT,
				ALUARI;
	
	assign ALUCMP = (IWORD[28]);
	assign CMPLT = ALUCMP && (IWORD[26]);
	assign CMPEQ = ALUCMP && !(CMPLT && !IWORD[25]);
	assign CMPNOT = /*ALUCMP && */(CMPEQ && !CMPLT) && IWORD[25];
	
	assign ALUARI = (IWORD[29] || IWORD[30] || (IWORD[31] && !IWORD[28]));
	
	assign ALULOG = (!ALUCMP && !ALUARI);
	assign LOGAND = ((ALULOG) && (!IWORD[27] && !IWORD[26]));
	assign LOGOR = ((ALULOG) && (IWORD[26]));
	assign LOGXOR = ((ALULOG) && (IWORD[27]));
	assign LOGNOT = ((LOGAND && IWORD[25]) || (LOGOR && IWORD[25]));

	assign ADDSUB = (CMPLT) || (ALUARI && IWORD[25]); 
endmodule

module CtlWMem(IWORD,WMEM,RMEM);
  input  wire [31:0] IWORD;
  output wire WMEM,RMEM;
  wire isLW = IWORD[30] && !IWORD[29];
  wire isSW = IWORD[30] && IWORD[29];
  assign WMEM = isSW;
  assign RMEM = isLW;
endmodule

module BraCtl(IWORD,ISBRANCH,ISJUMP,SAVEPC);
  input  wire [31:0] IWORD;
  output wire ISBRANCH,ISJUMP,SAVEPC;
  
  assign ISBRANCH= (IWORD[31] && IWORD[28]);
  assign ISJUMP=(IWORD[31] && !IWORD[28]);
  assign SAVEPC=ISJUMP && !ISBRANCH;
endmodule

module sysCallCtl(IWORD, WRITECTL0, READCTL0, WRITECTL1, READCTL1);
	input [31:0] IWORD;
	output wire WRITECTL0, WRITECTL1;
	output wire READCTL0, READCTL1;
	assign WRITECTL0 = (IWORD[31:28]==4'h7 && `RD_BITS!=4'h1) ? 1'b1: 1'b0;
	assign READCTL0 = (IWORD[31:28]==4'h5 && `RS_BITS!=4'h1) ? 1'b1: 1'b0;
	assign WRITECTL1 = 1'b0; //FIX LATER (IWORD[31:28]==4'h7 && `RD_BITS==4'h1) ? 1'b1: 1'b0;
	assign READCTL1 = (IWORD[31:28]==4'h5 && `RS_BITS==4'h1) ? 1'b1: 1'b0;
endmodule


module Assign4(SW,KEY,HEX0,HEX1,HEX2,HEX3,CLOCK_50); 
	input  [9:0] SW;
	input  [3:0] KEY;
	input  CLOCK_50;
	output [6:0] HEX0,HEX1,HEX2,HEX3;

	wire [6:0] digit0,digit1,digit2,digit3;

	//wire clk, lock;
	
	
	wire lock=1;
	wire clk=CLOCK_50;
	//wire clk = !KEY[0];
	
	wire [3:0] keys=KEY;
	wire [9:0] switches=SW;

	assign {HEX0,HEX1,HEX2,HEX3}={digit0,digit1,digit2,digit3};
	parameter DBITS=32;
	
	
	
	  wire [(DBITS-1):0] abus;
  tri  [(DBITS-1):0] dbus;
  wire               we;

  reg [3:0] CTL0; //Bit 0 is IE Bit 1 is OIE Bit 3 is CM Bit 4 is OM
  reg [3:0] CTL1; //holds ID of device
  // Address bus is driven with the memaddr value
  wire [31:0] memaddr_M;
  assign memaddr_M = aluout_M;
  assign abus=memaddr_M;
  // The write-enable signal is driven with the wmem value
  assign we=wmem_M;
  // The data bus is driven by the processor only when writing
  // (When reading, dbus is driven by memory/device we read from)
  assign dbus=wmem_M?regout2_M:{DBITS{1'bz}};

  // This replaces the MemSys module - we now only have memory in its module, other
  // memory-mapped devices have their own modules
  Memory #(.BITS(DBITS),.RABITS(13),.MFILE("Test5.mif"))
  memory(.IADDR(PC_F),.IOUT(inst_F),
         .ABUS(abus),.DBUS(dbus),.WE(we),
         .CLK(clk),.LOCK(lock),.INIT(init));
  
  wire intr_timer;
  // DIVN is set for 25MHz, it tells the timer how many cycles need to pass
  // before it can decrement TCNT - and hose decrements need to happen 1000 times per second
  // If you change the frequency, remember to change the timer's DIVN to still have TCNT
  // be decremented at 1000 times per second
  Timer #(.BITS(DBITS),.BASE(32'hFFFFF100),.DIVN(25000),.DIVB(17))
  timer(.ABUS(abus),.DBUS(dbus),.WE(we),.INTR(intr_timer),.CLK(clk),.LOCK(lock),.INIT(init),.DEBUG(ledgreen));

  Display #(.BITS(DBITS),.BASE(32'hFFFFF800))
  display(.ABUS(abus),.DBUS(dbus),.WE(we),.CLK(clk),.LOCK(lock),.INIT(init),
          .HEX0(digit0),.HEX1(digit1),.HEX2(digit2),.HEX3(digit3));
          //REMEMBER TO MODIFY BACK
  
  //Leds #(.ABITS(DBITS),.DBITS(DBITS),.LBITS(10),.BASE(32'hFFFFF804))
 // ledsr(.ABUS(abus),.DBUS(dbus),.WE(we),.CLK(clk),.LOCK(lock),.INIT(init),.LED(ledred));
  
 // Leds #(.ABITS(DBITS),.DBITS(DBITS),.LBITS(8),.BASE(32'hFFFFF808))
  //ledsg(.ABUS(abus),.DBUS(dbus),.WE(we),.CLK(clk),.LOCK(lock),.INIT(init),.LED(ledgreen));
  
  wire intr_keys=1'b0;
  //KeyDev #(.BITS(DBITS),.BASE(32'hFFFFF000))
  //keyDev(.ABUS(abus),.DBUS(dbus),.WE(we),.INTR(intr_keys),.CLK(clk),.LOCK(lock),.INIT(init),.KEY(keys),.DEBUG());
  
  wire intr_sws=1'b0;
  wire sws;
  // DEBN tells the SW device how many cycles must pass until a change in raw SW state is considered debounced
  // (At 25MHz, there are 250,000 cycles in 10ms; if you change the frequency, change DEBN here, too)
 // SwDev #(.BITS(DBITS),.BASE(32'hFFFFF004),.DEBN(18'd250000),.DEBB(18))
  //swDev(.ABUS(abus),.DBUS(dbus),.WE(we),.INTR(intr_sws),.CLK(clk),.LOCK(lock),.INIT(init),.SW(sws),.DEBUG());
  
  // Illegal instruction signal generated and used in R stage
  // Note how we don't signal an illegal instruction if we're hoing to
  // flush it because a mispredicted branch is in the A stage
  wire iinst_R=iinst_raw&&(!mispred_A);
  // Determine mode using the instruction word and current mode
  // CtlIInst simply looks at the instruction word and decides if it's legal
  // in the current mode (cmode_R, which is tied to CTL0[2])
  wire iinst_raw;
  wire cmode_R=(!isWctl0_A) ? CTL0[2] : regout1_A[2];
  wire isWctl0_R, isRctl0_R, isWctl1_R, isRctl1_R;
  CtlIInst ctlIInst(.IWORD(inst_R),.CMODE(cmode_R),.IINST(iinst_raw));
  
  sysCallCtl sysCtl(.IWORD(inst_R),.WRITECTL0(isWctl0_R), .READCTL0(isRctl0_R),.WRITECTL1(isWctl1_R), .READCTL1(isRctl1_R));
	
  // We want to have an interrupt or exception if we have an illegal instruction (regardless of IE),
  // or if we have an interrupt request while interrupts are enabled (CTL0[0]) and while we are not already
  // in the process of jumping to the interrupt handler
  wire intr=iinst_R ||(CTL0[0]&&(!inta_A)&&(intr_timer||intr_keys||intr_sws));
  // This is where we determine the number to put in CTL1
  // In my implementation CTLx are read/written in the A stage,
  // so I have an iinst_A signal to indicate that an instruction
  // that was detected as illegal (and was killed) is now in A stage
  wire [3:0] intn=
    iinst_A   ?4'h0:
    intr_timer?4'h1:
    intr_keys? 4'h2:
    intr_sws?  4'h3:
               4'hF;		
				

	// Program Counter (value used in F stage, updated using inputs from F and A stages)
	reg  [(DBITS-1):0] PC; //=32'h400;//400;
	// We update the PC only if clock signal is locked
	// Note that jumps and taken branches update the PC two cycles late, so the two instructions
	// that follow a jump or taken branch are executed anyway (effectively, we have two delay slots)

	
	reg init=1'b1;
	always @(posedge clk) if(lock) begin
		init<=1'b0;
	end
	
	wire [DBITS:0] brTarget;
	BranchTable #(.DBITS(DBITS+1),.ABITS(8),.MFILE("Assign4BPR.mif"))
		brTable(.RADDR1(PC_F[7:0]),.DOUT1(brTarget),
				.WADDR(prevPC_A[7:0]),.DIN(brTableUpdate),
				.WE(ctrlflush_A),
				.CLK(clk));
	
	always @(posedge clk) if(lock) begin
		PC <= (init) ? 32'h400:
			  (inta_A) ? 32'h200 :
			  (ctrlflush_A) ? PCcorr_A:
			  (stall_R) ? PC_F :
						PCpred_F;
		CTL0<=(init) ? 4'b0100 :
			  (inta_A) ? {CTL0[2],1'b1,CTL0[0],1'b0} :
			  (isWctl0_A) ? regout1_A[3:0] : 
										CTL0;
		CTL1 <=
				(inta_A) ? intn :
				(isWctl1_A) ? regout1_A[3:0] :
							CTL1;
	end
	
	//not sure which pc so set for predicted
	wire [(DBITS-1):0] PCpred_F = (!brTarget[32:32])? PC4_F : brTarget[31:0];
	
	wire [(DBITS-1):0] PC_F=PC;
	// PC+4 generated in the F stage (used in F to update PC, also used for branch and JRL insts in later stages)
	wire [(DBITS-1):0] PC4_F=PC_F+32'd4;
	
	// Register file, read in R stage, written in W stage
	// Register file, read in R stage, written in W stage **AND ALU stage to support for interupts
	RegFile  #(.DBITS(DBITS),.ABITS(4),.MFILE("Assign5R.mif"))
		regFile(.RADDR1(rregno1_R),.DOUT1(regout1_R),
				.RADDR2(rregno2_R),.DOUT2(regout2_R),
				.WADDR1(wregno_W),.DIN1(regval_W), 
				.WADDR2(wadd2),.DIN2(r2din),
				.WE1(wrreg_W),
				.WE2(isRctl0_A||isRctl1_A|| inta_A),
				.CLK(clk));
		wire [31:0] r2din = 
							(inta_A) ? prevPC_A: //PCcorr_A://prevPC_A :
							(isRctl0_A) ? CTL0:
							(isRctl1_A) ? CTL1:
										32'hXXXXXXXX;
		wire [3:0] wadd2 = 
							inta_A ? 4'hC :
							(isRctl0_A||isRctl1_A) ? wregno_A:
													4'hX;
				/*old mem
	MemSys #(.DBITS(DBITS),.RABITS(13),.MFILE("Assign4.mif"))
		memSys(.IAddr(PC_F),.IOut(inst_F),
			   .DAddr(aluout_M),.DIn(regout2_M),.DOut(memout_M),.DWE(wmem_M),
			   .CLK(clk),
			   .KEY(keys),.SW(switches),
			   .HEX0(digit0),
			   .HEX1(digit1),
			   .HEX2(digit2),
			   .HEX3(digit3));*/
	// Instruction word, generated (from MemSys, see above) in the FE stage
	wire [(DBITS-1):0] inst_F;
	// Register numbers for reading generated and used in F stage
	wire [3:0] rregno1_F,rregno2_F;
	CtlRReg ctlRReg(.IWORD(inst_F),.RREGNO1(rregno1_F),.RREGNO2(rregno2_F));

	// Pipeline registers between F and R stages
	reg [(DBITS-1):0] inst_R=32'b0,PC4_R;
	reg [3:0] rregno1_R,rregno2_R;
	reg [(DBITS-1):0] PCpred_R, prevPC_R;
	// Get new F->R signals each locked clock cycle
	always @(posedge clk) if(lock) begin
		{prevPC_R, PC4_R, PCpred_R, rregno1_R,rregno2_R,inst_R} <= 
								(init || ctrlflush_A) ? {32'b0, 32'b0, 32'b0, 4'b0,4'b0,32'b0}:
											(stall_R) ? {prevPC_R, PC4_R, PCpred_R, rregno1_R,rregno2_R,inst_R}:
															{PC_F, PC4_F, PCpred_F, rregno1_F,rregno2_F,inst_F};
	end

	// Register outputs generated in R stage (from RegFile, see above), used in subsequent stages
	wire [(DBITS-1):0] regout1_R,regout2_R;
	// Immediate value sign-extension and *4 (if needed) is done in R and used in R (for ALU) and A (for branches)
	wire [(DBITS-1):0] immval_R;
	CtlImm #(.DBITS(DBITS)) ctlImm(.IWORD(inst_R),.IMMVAL(immval_R));

	// Control for the second ALU input value (reg, imm, or zero) is generated in R, used in R
	// aluin2i decides between register and non-register value for ALU input 2; it is used in A
	// aluin2z selects between sxt(imm) and zero for the non-reg value; it is used in R
	// Note that aluin2z matters only when aluin2i is 1
	wire aluin2z_R,aluin2i_R;
	CtlALUIn ctlALUIn(.IWORD(inst_R),.ALUIN2Z(aluin2z_R),.ALUIN2I(aluin2i_R));
	// If non-reg used as second ALU input value, it is zero or sxt(imm). We select between them in R
	// The result of this selection goes to A stage, where we select between it and regout2
	wire [(DBITS-1):0] aluimm_R=aluin2z_R?32'd0:immval_R;

	// ALU function controls generated in R, used in A stage
	// Logic result enabled if alulog is 1
	// Logic operation selected by aluand,aluor,aluxor
	// Logic result inverted if lognot is 1
	wire alulog_R,logand_R,logor_R,logxor_R,lognot_R;
	// Arithmetic and comparison operations use the adder/subtractor
	// It adds if addsub is 0, subtracts otherwise
	wire addsub_R;
	// Comparison result enabled if alucmp is 1
	// Comparison result is eq, lt, or both (le)
	// Comparison result inverted if cmpnot_g is 1
	wire alucmp_R,cmpeq_R,cmplt_R,cmpnot_R;
	// Enables arithmetic result (ALU result comes directly from the adder/subtractor)
	wire aluari_R;
	CtlALU ctlALU(.IWORD(inst_R),.ALULOG(alulog_R),.LOGAND(logand_R),.LOGOR(logor_R),
				.LOGXOR(logxor_R),.LOGNOT(lognot_R),.ADDSUB(addsub_R),.ALUCMP(alucmp_R),
				.CMPEQ(cmpeq_R),.CMPLT(cmplt_R),.CMPNOT(cmpnot_R),.ALUARI(aluari_R));

	// Branch/jump control signals generated in R, used in A stage
	wire isbranch_R,isjump_R,savepc_R;
	BraCtl braCtl(.IWORD(inst_R),.ISBRANCH(isbranch_R),.ISJUMP(isjump_R),.SAVEPC(savepc_R));

	// Memory read and write control (generated in R, used in M and W stages)
	wire wmem_R,rmem_R;
	CtlWMem ctlWMem(.IWORD(inst_R),.WMEM(wmem_R),.RMEM(rmem_R));

	// Register write control, generated in R and used in W stages
	wire [3:0] wregno_R;
	wire wrreg_R;
	CtlWReg ctlWReg(.IWORD(inst_R),.WREGNO(wregno_R),.WRREG(wrreg_R));
  
	//DATA HAZARD
	//check to see if there is a data hazard dependency
	wire ddep1A_R=wrreg_A && (rregno1_R==wregno_A);
	wire ddep1M_R=wrreg_M && (rregno1_R==wregno_M);
	wire ddep2A_R=(wmem_R || !aluin2i_R) && (wrreg_A) && (rregno2_R==wregno_A); //
	wire ddep2M_R=(wmem_R || !aluin2i_R) && (wrreg_M) && (rregno2_R==wregno_M); //(
	
	
	//LW dependancy, manditory stall  r(I) | a(LW) | Mem | WB
	wire stall_R=(rmem_A && (ddep1A_R||ddep2A_R) );// || (ddep2A_R) || (ddep2M_R);
	//wire ddep3A_M=rmem_A&&(ddep1A_R||ddep2A_R); // && rmem_R;
	//wire stall_R=(ddep1A_R||ddep1M_R||ddep2A_R||ddep2M_R||ddep3A_M);//ddep3M_M);
  
	/* registers from R to A */
	reg [(DBITS-1):0] PC4_A, regout1_A, regout2_A, immval_A, aluimm_A;
	reg aluin2i_A, alulog_A, logand_A, logor_A, logxor_A, lognot_A;
	reg addsub_A, alucmp_A, cmpeq_A, cmplt_A, cmpnot_A;
	reg aluari_A, isbranch_A, isjump_A, savepc_A;
	reg wmem_A, rmem_A, wrreg_A;
	reg [3:0] wregno_A;
	reg isWctl0_A, isRctl0_A, isWctl1_A, isRctl1_A, inta_A;
	reg iinst_A;
	reg [3:0] intn_A;
    reg [(DBITS-1):0] PCpred_A, prevPC_A;
    
	always @(posedge clk) if(lock) begin
		
			regout1_A <= (!init)&&(ddep1A_R && rmem_A) ? 32'b0 : 
						 (!init)&&(ddep1A_R && savepc_A) ? PC4_A:
						 (!init)&&(ddep1A_R) ? aluout_A:
						 (!init)&&(ddep1M_R) ? regval_M:
						 (!init) 			 ? regout1_R:
											32'hXXXXXXXX;
								 
			regout2_A <= (!init)&&(ddep2A_R && rmem_A) ? 32'b0 : 
						 (!init)&&(ddep2A_R && savepc_A) ? PC4_A:
						 (!init)&&(ddep2A_R) ? aluout_A:
						 (!init)&&(ddep2M_R) ? regval_M:
						 (!init) 			 ? regout2_R:
											32'hXXXXXXXX;
					 
			
			{isbranch_A,isjump_A,wmem_A,wrreg_A, savepc_A, rmem_A, iinst_A, isWctl0_A, isRctl0_A, isWctl1_A, isRctl1_A, inta_A, intn_A} <= ( (ctrlflush_A || stall_R || init || inta_A)) ? 16'h0000:
													{isbranch_R,isjump_R,wmem_R,wrreg_R, savepc_R, rmem_R, iinst_R, isWctl0_R, isRctl0_R, isWctl1_R, isRctl1_R, intr, intn};	
			
			
			{immval_A,	aluin2i_A	} <= (!init) ? {immval_R,	aluin2i_R} : {32'hXXXXXXXX,	1'bX};
			{aluimm_A,	alulog_A,	logand_A,	logor_A		} <= (!init) ? {aluimm_R,		alulog_R, 	logand_R, logor_R} : {1'bX,1'bX, 1'bX,1'bX};
			{logxor_A,	lognot_A,	addsub_A,	alucmp_A	} <= (!init) ? {logxor_R,		lognot_R,	addsub_R, alucmp_R} : {1'bX,1'bX,1'bX,1'bX};
			{cmpeq_A,	cmplt_A,	cmpnot_A,	aluari_A	} <= (!init) ? {cmpeq_R,		cmplt_R,	cmpnot_R, aluari_R} : {1'bX,1'bX,1'bX,1'bX};
			{wregno_A,	PC4_A, 		PCpred_A,	prevPC_A	} <= (!init) ? {wregno_R,		PC4_R, 		PCpred_R, prevPC_R} : {4'bX,32'b0, 32'b0, 32'b0};
		
	end

	/* ALU */
	// ALU input values (generated and used in A stage)
	wire [(DBITS-1):0] aluin1_A=regout1_A;
	wire [(DBITS-1):0] aluin2_A=aluin2i_A?aluimm_A:regout2_A;
	// The ALU generates its result in the A stage, it is used in A, M,and W stages
	// Generate logic result (or zero if  select it or ignore it)
	wire [(DBITS-1):0] andout_A={DBITS{logand_A}}&(aluin1_A&aluin2_A);
	wire [(DBITS-1):0] orout_A ={DBITS{logor_A }}&(aluin1_A|aluin2_A);
	wire [(DBITS-1):0] xorout_A={DBITS{logxor_A}}&(aluin1_A^aluin2_A);
	wire [(DBITS-1):0] logtmp_A=(andout_A|orout_A|xorout_A);
	wire [(DBITS-1):0] logres_A=lognot_A?(~logtmp_A):logtmp_A;
	wire [(DBITS-1):0] logout_A=logres_A&{DBITS{alulog_A}};
	// This is our adder/subtractor (if subtract, invert 2nd input, add 1)
	wire [(DBITS-1):0] arires_A=aluin1_A+(addsub_A?(~aluin2_A):aluin2_A)+addsub_A;
	wire [(DBITS-1):0] ariout_A=arires_A&{DBITS{aluari_A}};
	// Generate comparison result (lt uses subtration result, so addsub must be 1 for lt or lte)
	wire eqout_A=cmpeq_A&&(aluin1_A==aluin2_A);
	wire ltout_A=cmplt_A&&arires_A[31];
	wire cmptmp_A=eqout_A||ltout_A;
	wire cmpres_A=cmpnot_A?(!cmptmp_A):cmptmp_A;
	wire [(DBITS-1):0] cmpout_A={{(DBITS-1){1'b0}},cmpres_A&&alucmp_A};
	// Final ALU result
	wire [(DBITS-1):0] aluout_A=logout_A|ariout_A|cmpout_A;
  
	// Put your code here to generate these signals:
	// PCBT_A (target address for a branch, will be used only if this is a taken branch)
	wire [(DBITS-1):0] PCBT_A = (PC4_A+immval_A);

	//PCJT_A (target address for a jump, will be used only if this is a jump)
	wire [(DBITS-1):0] PCJT_A = aluout_A;

	//usebtarg_A (one-bit signal that is set to 1 if this is a taken branch)
	wire usebtarg_A = isbranch_A?aluout_A[0]:1'b0;
	//usejtarg_A (one-bit signal that is set to 1 if this is a jump)
	wire usejtarg_A = isjump_A;
	
	//CONTROL HAZARD
	//detect if a branch or jump is going to occur
	
	wire [(DBITS-1):0] PCcorr_A=
							usebtarg_A?PCBT_A:
							usejtarg_A?PCJT_A:
							PC4_A;
	wire [(DBITS):0] brTableUpdate = {{1'b1},{PCcorr_A}};	
	wire ctrlflush_A=(PCpred_A!=PCcorr_A);
	wire mispred_A=ctrlflush_A;
	//wire ctrlflush_A = usebtarg_A || usejtarg_A;
  
	//registers from A to M
	//generating all the wires
	reg [(DBITS-1):0] PC4_M, aluout_M, regout2_M;
	reg savepc_M, wrreg_M, wmem_M, rmem_M;
	reg [3:0] wregno_M;
	
	
	
	
	
	
	
	
	always @(posedge clk) if(lock) begin
		{PC4_M,	aluout_M,savepc_M,wregno_M} <= (!init) ? {PC4_A,aluout_A,savepc_A,wregno_A} : {32'hXXXXXXXX, 32'hXXXXXXXX, 1'b0, 4'hX};
		{wrreg_M,wmem_M, regout2_M,rmem_M} <= (!init) ? {wrreg_A,wmem_A,regout2_A,rmem_A} : {1'b0, 1'b0, 4'hX, 1'b0};
	end

	// Memory output generated in M, used in W
	wire [(DBITS-1):0] memout_M;//=rmem_M?memout_M:32'bZ;
	// For non-memory results, choose between ALU result and PC+4
	wire [(DBITS-1):0] nonmem_M=savepc_M?PC4_M:aluout_M;

	//registers from M to W
	//generating all the wires
	reg [(DBITS-1):0] memout_W, nonmem_W;
	reg [3:0] wregno_W;
	wire [(DBITS-1):0] regval_M = rmem_M?dbus:nonmem_M;
	reg wrreg_W, rmem_W;
	always @(posedge clk) if(lock) begin
		{memout_W,	nonmem_W,	wregno_W,	wrreg_W	} <= (!init) ? {dbus, nonmem_M, wregno_M, wrreg_M} : {32'hXXXXXXXX, 32'hXXXXXXXX, 4'hX, 1'b0};
		{rmem_W} <= (!init) ? {rmem_M} : 1'b0;
	end

	//W Stage
	wire [(DBITS-1):0] regval_W = rmem_W?memout_W:nonmem_W;
	//Note that the code that connects the register write signals to the register
	//file is already there in the instantiation of the RegFile module (see above)
	
    
endmodule

//changed this to double write reg file as well for CTL reading
module RegFile(RADDR1,DOUT1,RADDR2,DOUT2,WADDR1,DIN1, WADDR2, DIN2, WE1,WE2,CLK);
  parameter DBITS; // Number of data bits
  parameter ABITS; // Number of address bits
  parameter WORDS = (1<<ABITS);
  parameter MFILE = "";
  (* ram_init_file = MFILE *)
  reg [(DBITS-1):0] mem[(WORDS-1):0];
  input  [(ABITS-1):0] RADDR1,RADDR2,WADDR1, WADDR2;
  input  [(DBITS-1):0] DIN1, DIN2;
  output wire [(DBITS-1):0] DOUT1,DOUT2;
  input CLK,WE1, WE2;
  always @(posedge CLK) begin
    if(WE1) begin
      mem[WADDR1]=DIN1;
    end
    if(WE2)begin
	  mem[WADDR2]=DIN2;
	end
  end
  assign DOUT1=(WE1&&(WADDR1==RADDR1)) ? DIN1:
			   (WE2&&(WADDR2==RADDR1)) ? DIN2:
								mem[RADDR1];
  assign DOUT2=(WE1&&(WADDR1==RADDR2)) ? DIN1: 
			   (WE2&&(WADDR2==RADDR2)) ? DIN2:
								mem[RADDR2];
endmodule

module MemSys(IAddr,IOut,DAddr,DOut,DIn,DWE,CLK,KEY,SW,HEX0,HEX1,HEX2,HEX3);
  // File to initialize memory with
  parameter MFILE;
  // Number of bits in a memory word
  parameter DBITS;
  // Number of bits in the physical address
  parameter PABITS=DBITS;
  // Number of bits in the real address
  parameter RABITS;
  parameter RWORDS=(1<<(RABITS-2));
  input wire  [(PABITS-1):0] IAddr,DAddr;
  input wire  [(DBITS-1):0] DIn;
  input wire  DWE,CLK;
  output wire [(DBITS-1):0] IOut,DOut;
  input  wire [3:0] KEY;
  input  wire [9:0] SW;
  output wire [6:0] HEX0,HEX1,HEX2,HEX3;
  // Real memory
  (* ram_init_file = MFILE *) (* ramstyle="no_rw_check" *)
  reg [(DBITS-1):0] marray[RWORDS];
  // Hex display
  // Note how you can use SW[9] to see the upper 16 bits of
  // the 32-bit value written to the hex display I/O address
  reg [31:0] HexOut=31'h6789ABCD;
  SevenSeg ss3(.OUT(HEX3),.IN(SW[9]?HexOut[31:28]:HexOut[15:12]));
  SevenSeg ss2(.OUT(HEX2),.IN(SW[9]?HexOut[27:24]:HexOut[11: 8]));
  SevenSeg ss1(.OUT(HEX1),.IN(SW[9]?HexOut[23:20]:HexOut[ 7: 4]));
  SevenSeg ss0(.OUT(HEX0),.IN(SW[9]?HexOut[19:16]:HexOut[ 3: 0]));
  assign DOut=
    (DAddr[(PABITS-1):RABITS]=={(PABITS-RABITS){1'b0}})?marray[DAddr[(RABITS-1):2]]:
    (DAddr==32'hFFFFF000)?{28'b0,KEY}://SW[3:0]}://KEY}:
    (DAddr==32'hFFFFF004)?{22'b0,SW}:
    32'hXXXXXXXX;
  assign IOut=
    (IAddr[(PABITS-1):RABITS]=={(PABITS-RABITS){1'b0}})?marray[IAddr[(RABITS-1):2]]:
    32'hXXXXXXXX;
  always @(posedge CLK) begin
    if(DWE) begin
      if(DAddr[(PABITS-1):RABITS]=={(PABITS-RABITS){1'b0}})
        marray[DAddr[(RABITS-1):2]]=DIn;
      else if(DAddr==32'hFFFFF800)
        HexOut<=DIn[15:0];
    end
  end
endmodule

module SevenSeg(OUT, IN);
	output[6:0] OUT;
	input [7:0] IN;
	assign OUT=
		(IN == 4'd0) ? 7'b1000000 :
		(IN == 4'd1) ? 7'b1111001 :
		(IN == 4'd2) ? 7'b0100100 :
		(IN == 4'd3) ? 7'b0110000 :
		(IN == 4'd4) ? 7'b0011001 :
		(IN == 4'd5) ? 7'b0010010 :
		(IN == 4'd6) ? 7'b0000010 :
		(IN == 4'd7) ? 7'b1111000 :
		(IN == 4'd8) ? 7'b0000000 :
		(IN == 4'd9) ? 7'b0010000 :
		(IN == 4'd10) ? 7'b0001000 :
		(IN == 4'd11) ? 7'b0000011 :
		(IN == 4'd12) ? 7'b1000110 :
		(IN == 4'd13) ? 7'b0100001 :
		(IN == 4'd14) ? 7'b0000110 :
		(IN == 4'd15) ? 7'b0001110 :
					    7'b0110000 ;
					    
endmodule


module BranchTable(RADDR1,DOUT1,WADDR,DIN,WE,CLK);
  parameter DBITS; // Number of data bits
  parameter ABITS; // Number of address bits
  parameter WORDS = (1<<ABITS);
  parameter MFILE = "";
  (* ram_init_file = MFILE *)
  reg [(DBITS-1):0] mem[(WORDS-1):0];
  input  [(ABITS-1):0] RADDR1,WADDR;
  input  [(DBITS-1):0] DIN;
  output wire [(DBITS-1):0] DOUT1;
  input CLK,WE;
  always @(posedge CLK)
    if(WE)
      mem[WADDR]=DIN;
  assign DOUT1=(WE&&(WADDR==RADDR1))?DIN:mem[RADDR1];
endmodule
//ASSIGN 5 MODULES INCLUDING NEW MEMORY

module Memory(IADDR,IOUT,ABUS,DBUS,WE,CLK,LOCK,INIT);
  // File to initialize memory with
  parameter MFILE;
  // Number of bits in a memory word
  parameter BITS;
  // Number of bits in the real address
  parameter RABITS;  
  parameter RWORDS=(1<<(RABITS-2));
  input wire [(BITS-1):0] IADDR,ABUS;
  output wire [(BITS-1):0] IOUT;
  inout wire [(BITS-1):0] DBUS;
  input wire WE,CLK,LOCK,INIT;
  // does address refer to actual memory
  wire selMem=(ABUS[(BITS-1):RABITS]=={(BITS-RABITS){1'b0}});
  // Will we write a memory location?
  wire wrMem=WE&&selMem;
  // Should we drive a value from memory to the bus?
  wire rdMem=(!WE)&&selMem;
  // Real memory
  (* ram_init_file = MFILE *) (* ramstyle="no_rw_check" *)
  reg [(BITS-1):0] marray[RWORDS];
  always @(posedge CLK) if(LOCK) begin
    if(INIT) begin
    end else begin
      if(wrMem)
        marray[ABUS[(RABITS-1):2]]<=DBUS;
    end
  end
  // This should be familiar
  assign DBUS=rdMem?marray[ABUS[(RABITS-1):2]]:
                    {BITS{1'bz}};
  // Instructions have their own read port that does not go to the data bus
  assign IOUT=
    (IADDR[(BITS-1):RABITS]=={(BITS-RABITS){1'b0}})?
    marray[IADDR[(RABITS-1):2]]:
    32'hDEADBEEF;
endmodule

// Timer device
module Timer(ABUS,DBUS,WE,INTR,CLK,LOCK,INIT,DEBUG);
	parameter BITS;
	parameter BASE;
	parameter DIVN;
	parameter DIVB;
	input wire [(BITS-1):0] ABUS;
	inout wire [(BITS-1):0] DBUS;
	input wire WE,CLK,LOCK,INIT;
	output wire INTR;
	// This can be used for debugging, just connect the DEBUG
	// output from this device to LEDG :)
	// Nut note how it remains unconnected in the instantiation above!
	output wire [7:0] DEBUG={TCNT[13:10],OR,AR,IP,IE};
	// This is our TCTL, but I chose to keep it as separate bits
	reg OR,AR,IP,IE;
	// TINI and TCNT registers
	reg [(BITS-1):0] TINI,TCNT;
	// Does the address refer to our TCTL or TCNT/TINI registers?
	wire selCtl=(ABUS==BASE);
	wire selCnt=(ABUS==BASE+3'h4);
	// Write and read enable signals for each of these
	wire wrCtl=WE&&selCtl;
	wire wrCnt=WE&&selCnt;
	wire rdCtl=(!WE)&&selCtl;
	wire rdCnt=(!WE)&&selCnt;
	
	reg [(DIVB-1):0] tmpCount; //= DIVN;
	reg counting; //used to only throw an interrupt after we start counting
	
	always @(posedge CLK) if(LOCK) begin
	
		if(INIT) begin //init the timer
			{IE,IP,AR,OR} <= {1'b0, 1'b0, 1'b0, 1'b0};
			TINI <= 32'd0;
			TCNT <= 32'd0;
			counting <= 1'b0;
			tmpCount = DIVN;
		end
		else if(wrCtl) begin //write to the "Control" register
			//not sure about this
			//{OR,IE,IP,AR} <={DBUS[6:4],DBUS[7]};
			//OR,AR,IP,IE
			{IE,IP,AR,OR} <= {DBUS[0],DBUS[1],DBUS[2],DBUS[3]};
		end else if(wrCnt) begin //write to the "Count" register
			TCNT <= DBUS;
		end	else if(TCNT > 1'b0) begin //if the timer is > 0
			counting <= 1'b1; //flag that we've been counting
			if(tmpCount == 0) begin
				TCNT<=TCNT-1'b1; //decrease by a second
				tmpCount <= DIVN; //resent freq count
			end else begin
				tmpCount <= tmpCount-1'd1; //decrease freq count
			end
		end else if(counting) begin //if the timer reaches 0 after counting
			if(IP) OR <= 1'b1; //if we're already pending an interrupt, set overrun to true
			if(IE) IP <= 1'b1; //if interrupts are enabled, flag an interrupt
			
			TCNT <= AR?TINI:{(BITS){1'b0}}; //reset COUNT if auto restart is set, else leave at 0.
			counting <= AR?1'b1:1'b0; //update counting based on AR
			//NOTE: This will throw an OR if we're not using AR, is this OK?
		end
	end

	// Drive the bus only if processor is reading one of the two addresses
	// this device is responsible for
	assign DBUS=rdCtl?{{(BITS-4){1'b0}},OR,AR,IP,IE}:
			  rdCnt?TCNT:{BITS{1'bz}};
	// Ask for interrupt only if interrupt pending (IP) and enabled (IE)
	assign INTR=(IP&&IE);
endmodule

// This is the display device
module Display(ABUS,DBUS,WE,CLK,LOCK,INIT,HEX0,HEX1,HEX2,HEX3);
  parameter BITS;
  parameter BASE;
  input wire [(BITS-1):0] ABUS;
  inout wire [(BITS-1):0] DBUS;
  input wire WE,CLK,LOCK,INIT;
  output wire [6:0] HEX0,HEX1,HEX2,HEX3;
  reg [15:0] HexVal;
  SevenSeg ss3(.OUT(HEX3),.IN(HexVal[15:12]));
  SevenSeg ss2(.OUT(HEX2),.IN(HexVal[11: 8]));
  SevenSeg ss1(.OUT(HEX1),.IN(HexVal[ 7: 4]));
  SevenSeg ss0(.OUT(HEX0),.IN(HexVal[ 3: 0]));
  wire selDisp=(ABUS==BASE);
  wire wrDisp=WE&&selDisp;
  always @(posedge CLK) if(LOCK) begin
    if(INIT)
      HexVal<=16'hDEAD;
    else if(wrDisp)
      HexVal<=DBUS[15:0];
  end
endmodule

 // Determine mode using the instruction word and current mode
  // CtlIInst simply looks at the instruction word and decides if it's legal
  // in the current mode (cmode_R, which is tied to CTL0[2])
module CtlIInst(IWORD, CMODE, IINST);
	input wire [31:0] IWORD;
	input wire CMODE;
	output reg IINST;
	always@(IWORD or CMODE) begin
		case(`OP_BITS)
			`OP_NAND,`OP_OR,`OP_NOR,`OP_XOR,
			`OP_EQ,`OP_NE,`OP_LT,`OP_LE,
			`OP_ADD,`OP_SUB,
			`OP_ANDI,`OP_NANDI,`OP_ORI,`OP_NORI,`OP_XORI,
			`OP_EQI,`OP_NEI,`OP_LTI,`OP_LEI,
			`OP_ADDI,`OP_SUBI,
			`OP_LW,
			`OP_JRL,
			`OP_BEQZ,`OP_BNEZ, `OP_BNE, `OP_BEQ, `OP_SW,
			`OP_AND: begin
					IINST=1'b0;
			 end
			
			`OP_RCTL,
			`OP_WCTL: begin
					IINST = (!CMODE);
			 end
		default:
			IINST=1'b1;
		endcase
	end

endmodule
